package com.amtf.datafile2.cfg.std;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import com.amtf.datafile2.DataFieldDefinition;
import com.amtf.datafile2.DataRecord;
import com.amtf.datafile2.DataTableDefinition;

public abstract class StdDataTableDefinition<T extends DataFieldDefinition> extends StdDefinition implements DataTableDefinition<T> {
	protected static final String DEFAULT_COLNAME = "Column";

	protected boolean firstRowTitle = false;
	protected boolean titleAsColumnName = false;
	protected List<T> fieldDefinition = new ArrayList<T>();
	protected Class<? extends DataRecord> dataRecordClass = null;

	// protected String function = "";

	public StdDataTableDefinition(String name, Class<? extends DataRecord> dataRecordClass) {
		super(name);
		this.dataRecordClass = dataRecordClass;
	}

	public abstract StdDataTableDefinition<T> clone();

	public abstract DataRecord newDataRecordInstance();

	protected abstract T newDataFieldDefinition(String columnName);

	protected void copyTo(StdDataTableDefinition<T> cloneDef) {
		cloneDef.name = this.name;
		cloneDef.dataRecordClass = this.dataRecordClass;
		cloneDef.firstRowTitle = this.firstRowTitle;
		cloneDef.titleAsColumnName = this.titleAsColumnName;
		for (T def : fieldDefinition) {
			cloneDef.fieldDefinition.add((T) def.clone());
		}
	}

	public T getField(int index) {
		// int cape = (index + 1) - fieldDefinition.size();
		// if (cape > 0) {
		// for (int i = 0; i < cape; i++) {
		// fieldDefinition.add(new T("Column" + (fieldDefinition.size() + 1), this));
		// }
		// }
		if (index >= fieldDefinition.size()) {
			return null;
		}

		return fieldDefinition.get(index);
	}

	public T getField(String name) {
		for (T def : fieldDefinition) {
			if (def.getName().equalsIgnoreCase(name)) {
				return def;
			}
		}

		return null;
	}

	public T addField() {
		return (T) addField(DEFAULT_COLNAME + (fieldDefinition.size() + 1));
	}

	public List<T> addFields(int count) {
		List<T> newFieldDef = new ArrayList<T>();
		for (int i = 0; i < count; i++) {
			newFieldDef.add(addField());
		}

		return newFieldDef;
	}

	// public DataRecord newDataRecordInstance() {
	// try {
	// return (ExcelDataRecord) dataRecordClass.getConstructors()[0].newInstance(this);
	// } catch (Throwable e) {
	// // e.printStackTrace();
	// }
	//
	// return null;
	// }

	public void addFields(Collection<T> all) {
		for (T dataFieldDefinition : all) {
			fieldDefinition.add((T) dataFieldDefinition);
		}
	}

	public T addField(String columnName) {
		T newFd = newDataFieldDefinition(columnName);
		fieldDefinition.add(newFd);
		return newFd;
	}

	public T insertField(int index) {
		return insertField(index, DEFAULT_COLNAME + (fieldDefinition.size() + 1));
	}

	public T insertField(int index, String columnName) {
		T def = newDataFieldDefinition(DEFAULT_COLNAME + (fieldDefinition.size() + 1));
		fieldDefinition.add(index, def);
		return def;
	}

	public void removeField(int index) {
		fieldDefinition.remove(index);
	}

	public void removeField(String name) {
		for (int j = 0; j < fieldDefinition.size(); j++) {
			T def = fieldDefinition.get(j);
			if (def.getName().equalsIgnoreCase(name)) {
				fieldDefinition.remove(j);
				break;
			}
		}
	}

	public void removeAll() {
		fieldDefinition.clear();
	}

	public int getFieldCount() {
		return fieldDefinition.size();
	}

	public List<T> getFields() {
		return fieldDefinition;
	}

	public boolean isFirstRowTitle() {
		return firstRowTitle;
	}

	public void setFirstRowTitle(boolean firstRowTitle) {
		this.firstRowTitle = firstRowTitle;
	}

	public boolean isTitleAsColumnName() {
		return titleAsColumnName;
	}

	public void setTitleAsColumnName(boolean titleAsColumnName) {
		this.titleAsColumnName = titleAsColumnName;
	}

	public Class<? extends DataRecord> getDataRecordClass() {
		return dataRecordClass;
	}

	public void setDataRecordClass(Class<? extends DataRecord> dataRecordClass) {
		this.dataRecordClass = dataRecordClass;
	}

}
